package org.example.config;


import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.checkerframework.checker.units.qual.A;
import org.example.infrastructure.redis.IRedisService;
import org.example.types.annotation.DCCValue;
import org.example.types.common.Constants;
import org.example.types.enums.ResponseCode;
import org.example.types.exception.AppException;
import org.redisson.api.RBucket;
import org.redisson.api.RTopic;
import org.redisson.api.RedissonClient;
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

import static org.example.types.common.Constants.COLON;

/**
 * @author yinghuashen
 * @version 1.0
 * @description:
 * @date 2025/3/8 11:27
 */
@Slf4j
@Configuration
public class DCCFactory implements BeanPostProcessor {

    private final String DCC_TOPIC_NAME = "DCC_TOPIC";

    private final String DCC_PREFIX = "DCC:";

    private final Map<String, Object> dccMap = new HashMap<>();

    @Resource
    private RedissonClient redissonClient;

    @Resource
    private IRedisService redisService;

    @Bean("dccTopic")
    protected RTopic addDCCTopicListener() {
        RTopic topic = redissonClient.getTopic(DCC_TOPIC_NAME);
        topic.addListener(String.class, (channel, message) -> {
            // 收到的消息格式: {key,new_value}
            String[] split = message.split(COLON);
            String key = split[0];
            String redisKey = DCC_PREFIX + key;
            String newValue = split[1];

            // 更新map中的值
            redisService.setValue(redisKey, newValue);

            // 从map中获取bean
            Object obj = dccMap.get(key);
            if(obj == null){
                log.warn("未在dccGroup中找到对应的配置对象，key:{}", key);
                return;
            }

            // 更新bean的值
            // 反射设置属性值
//            if(AopUtils.isAopProxy(obj)){
//                obj = AopProxyUtils.getSingletonTarget(obj);
//            }
            try {
                Class<?> clazz = obj.getClass();
                Field field = clazz.getDeclaredField(key);
                field.setAccessible(true);
                field.set(obj, newValue);
                field.setAccessible(false);
            } catch (Exception e) {
                throw new AppException(ResponseCode.DYNAMIC_CONFIG_REFLECTION_ERROR);
            }
        });
        return topic;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        // 注意；增加 AOP 代理后，获得类的方式要通过 AopProxyUtils.getTargetClass(bean);
        // 不能直接 bean.class 因为代理后类的结构发生变化，这样不能获得到自己的自定义注解了。
        Object targetBeanObject = bean;
        if(AopUtils.isAopProxy(bean)){
            targetBeanObject = AopProxyUtils.getSingletonTarget(bean);
        }
        Class<?> targetBeanClass = targetBeanObject.getClass();

        // 遍历bean中有DCCValue注解的字段
        Field[] fields = targetBeanClass.getDeclaredFields();
        for(Field field : fields){
            // 过滤没有DCCValue注解的字段
            if(!field.isAnnotationPresent(DCCValue.class)){
                continue;
            }
            // 获取DCCValue注解中的value
            String DCCValue = field.getAnnotation(DCCValue.class).value();
            if (StringUtils.isBlank(DCCValue)) {
                throw new AppException(ResponseCode.DYNAMIC_CONFIG_INIT_ERROR);
            }

            // 分割DCCValue注解中的value
            String[] split = DCCValue.split(COLON);
            // 构造key
            String key = split[0];
            String redisKey = DCC_PREFIX.concat(split[0]);
            String value = split.length == 2 ? split[1] : null;

            // 从Redis中获取bucket
            RBucket<String> bucket = redissonClient.getBucket(redisKey);
            if(bucket.isExists()){
                // bucket存在：获取值，设置bean中字段
                value = bucket.get();
            }
            else{
                // bucket不存在：存入bucket，根据bean中的DCC注解，设置默认值
                bucket.set(split[1]);
            }

            // 反射设置属性值
            try {
                field.setAccessible(true);
                field.set(bean, value);
                field.setAccessible(false);
            } catch (Exception e) {
                throw new AppException(ResponseCode.DYNAMIC_CONFIG_INIT_ERROR);
            }
            // 放入dccObjGroup中
            dccMap.put(key, bean);
        }
        return bean;
    }
}
